package com.zndroid.widget.ImageView;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;

import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.AppCompatImageView;
import androidx.core.util.Pair;

import com.zndroid.widget.BuildConfig;

import java.util.LinkedList;

/**
 * 在指定位置画框
 * */
public class TargetImageView extends AppCompatImageView {
    private static final String TAG = "TargetImageView";

    private final int DEFAULT_COLOR = Color.GREEN;
    private final float DEFAULT_STROKE_WIDTH = 3.0f;
    private final Paint DEFAULT_PAINT = new Paint();

    private final @NonNull LinkedList<Pair<RectF, Paint>> rectList = new LinkedList<>();


    public TargetImageView(@NonNull Context context) {
        super(context);
        init();
    }

    public TargetImageView(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public TargetImageView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        setScaleType(ScaleType.FIT_CENTER);

        DEFAULT_PAINT.setAntiAlias(true);
        DEFAULT_PAINT.setDither(true);
        DEFAULT_PAINT.setStyle(Paint.Style.STROKE);
    }

    public TargetImageView addLock(@NonNull RectF rectF) {
        return this.addLock(rectF, DEFAULT_PAINT);
    }

    public TargetImageView addLock(@NonNull RectF rectF, @NonNull Paint paint) {
        return this.addLock(rectF.left, rectF.top, rectF.right, rectF.bottom, paint);
    }

    public TargetImageView addLock(float leftInOrigin, float topInOrigin, float rightInOrigin, float bottomInOrigin) {
        return this.addLock(leftInOrigin, topInOrigin, rightInOrigin, bottomInOrigin, DEFAULT_PAINT);
    }

    /**
     * 添加目标点
     *
     * @param leftInOrigin 相对于原图，left 位置点
     * @param topInOrigin 相对于原图，top 位置点
     * @param rightInOrigin 相对于原图，right 位置点
     * @param bottomInOrigin 相对于原图，bottom 位置点
     * @param paint 自定义画笔
     * */
    public TargetImageView addLock(float leftInOrigin, float topInOrigin, float rightInOrigin, float bottomInOrigin, @NonNull Paint paint) {
        innerMeasure(leftInOrigin, topInOrigin, rightInOrigin, bottomInOrigin, paint);
        return this;
    }

    /**
     * 目标点添加后进行绘制
     * */
    public void locking() {
        DBG("要绘制的目标数：" + rectList.size());
        DBG("\n");
        postInvalidate();
    }

    public void clearLockers() {
        rectList.clear();
        init();
        postInvalidate();
    }

    public void locking(@NonNull RectF rectF) {
        this.locking(rectF.left, rectF.top, rectF.right, rectF.bottom);
    }

    public void locking(@NonNull RectF rectF, @ColorInt int color, float strokeWidth) {
        this.locking(rectF.left, rectF.top, rectF.right, rectF.bottom, color, strokeWidth);
    }

    public void locking(float leftInOrigin, float topInOrigin, float rightInOrigin, float bottomInOrigin) {
        this.locking(leftInOrigin, topInOrigin, rightInOrigin, bottomInOrigin, DEFAULT_COLOR, DEFAULT_STROKE_WIDTH);
    }

    /**
     * 锁定目标点
     *
     * @param leftInOrigin 相对于原图，left 位置点
     * @param topInOrigin 相对于原图，top 位置点
     * @param rightInOrigin 相对于原图，right 位置点
     * @param bottomInOrigin 相对于原图，bottom 位置点
     * @param color 边框颜色
     * @param strokeWidth 边框宽度
     * */
    public void locking(float leftInOrigin, float topInOrigin, float rightInOrigin, float bottomInOrigin, @ColorInt int color, float strokeWidth) {
        DEFAULT_PAINT.setColor(color);
        DEFAULT_PAINT.setStrokeWidth(strokeWidth);

        locking(leftInOrigin, topInOrigin, rightInOrigin, bottomInOrigin, DEFAULT_PAINT);
    }

    /**
     * 锁定目标点
     *
     * @param leftInOrigin 相对于原图，left 位置点
     * @param topInOrigin 相对于原图，top 位置点
     * @param rightInOrigin 相对于原图，right 位置点
     * @param bottomInOrigin 相对于原图，bottom 位置点
     * @param paint 自定义画笔
     * */
    public void locking(float leftInOrigin, float topInOrigin, float rightInOrigin, float bottomInOrigin, @NonNull Paint paint) {
        innerMeasure(leftInOrigin, topInOrigin, rightInOrigin, bottomInOrigin, paint);
        locking();
    }

    private void innerMeasure(float leftInOrigin, float topInOrigin, float rightInOrigin, float bottomInOrigin, @NonNull Paint paint) {
        //获得ImageView中Image的真实宽高
        Drawable drawable = getDrawable();
        float width = 1.0f;
        float height = 1.0f;

        if (drawable instanceof BitmapDrawable) {
            width = ((BitmapDrawable)drawable).getBitmap().getWidth();
            height = ((BitmapDrawable)drawable).getBitmap().getHeight();
        } else {
            Log.w(TAG, "locking: not instanceof BitmapDrawable of attached drawable");
            return;
        }

        Rect drawRect = drawable.copyBounds();

        Matrix matrix = getImageMatrix();
        float[] values = new float[9];
        matrix.getValues(values);

        //相对于实际绘制缩放比例
        float sX = values[Matrix.MSCALE_X];
        float sY = values[Matrix.MSCALE_Y];

        //相对于实际绘制偏移量
        float tX = values[Matrix.MTRANS_X];
        float tY = values[Matrix.MTRANS_Y];

        //实际绘制的宽高
        float realImgShowWidth = drawRect.width() * sX;
        float realImgShowHeight = drawRect.height() * sY;

        //相对于原图显示在控件上的缩放比例
        float scaleX = realImgShowWidth / width;
        float scaleY = realImgShowHeight / height;

        RectF target = new RectF(
                tX + leftInOrigin * scaleX,
                tY + topInOrigin * scaleY,
                tX + rightInOrigin * scaleX,
                tY + bottomInOrigin * scaleY
        );

        rectList.add(new Pair<>(target, paint));

        DBG("图片原始大小:" + width + ", " + height + " padding: " + getPaddingLeft() + ", " + getPaddingTop() + ", " + getPaddingRight() + ", " + getPaddingBottom());
        DBG("控件宽高: " + getWidth() + ", " + getHeight());
        DBG("控件实际绘制宽高: " + realImgShowWidth + ", " + realImgShowHeight);
        DBG("控件实际绘制的缩放比例和偏移量: scale:" + sX + ", " + sY + " offset:" + tX +", " + tY);
        DBG("相对于原图缩放比例: " + scaleX + ", " + scaleY);
        DBG("计算后的四个点位置: " + target.left + ", " + target.top + ", " + target.right + ", " + target.bottom);
    }

    private void DBG(String dbg) {
        if (BuildConfig.DEBUG) {
            Log.i(TAG, "DBG: " + dbg);
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        for (Pair<RectF, Paint> it : rectList) {
            RectF mRectF = it.first;
            Paint mPaint = it.second;

            if (null == mRectF || null == mPaint) {
                continue;
            }

            // |
            //mPaint.setColor(Color.GREEN);// for testing
            canvas.drawLine(mRectF.left + getPaddingLeft(), mRectF.top + getPaddingTop(), mRectF.left + getPaddingLeft(), mRectF.bottom + getPaddingTop(), mPaint);

            // ——
            //mPaint.setColor(Color.RED);// for testing
            canvas.drawLine(mRectF.left + getPaddingLeft(), mRectF.top + getPaddingTop(), mRectF.right + getPaddingLeft(), mRectF.top + getPaddingTop(), mPaint);

            //   |
            //mPaint.setColor(Color.YELLOW);
            canvas.drawLine(mRectF.right + getPaddingLeft(), mRectF.top + getPaddingTop(), mRectF.right + getPaddingLeft(), mRectF.bottom + getPaddingTop(), mPaint);

            // __
            //mPaint.setColor(Color.BLUE);// for testing
            canvas.drawLine(mRectF.left + getPaddingLeft(), mRectF.bottom + getPaddingTop(), mRectF.right + getPaddingLeft(), mRectF.bottom + getPaddingTop(), mPaint);
        }
    }
}
